﻿using Repository;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Diagnostics;

namespace Repository
{
    /// <summary>
    /// mongodb 操作类
    /// </summary>
    public class Repository
    {
        private Context _mongoDbContext = null;


		public Repository(Context mongoDbContext = null)
        {
            _mongoDbContext = new Context();
            //_mongoDbContext = mongoDbContext != null ? mongoDbContext : new MongoDbContext();
        }

        /// <summary>
        /// The private GetCollection method
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <returns></returns>
        private IMongoCollection<TEntity> GetCollection<TEntity>()
        {
            return _mongoDbContext.GetCollection<TEntity>();
        }

        #region 添加

        /// <summary>
        /// 添加一个实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public Result AddOne<TEntity>(TEntity item) where TEntity : class, new()
        {
            var res = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                collection.InsertOne(item);
                res.Success = true;
                res.Message = "OK";
                return res;
            }
            catch (Exception ex)
            {
                res.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return res;
            }
        }



        /// <summary>
        /// 添加一个实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public async Task<Result> AddOneAsync<TEntity>(TEntity item) where TEntity : class, new()
        {
            var res = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                await collection.InsertOneAsync(item);
                res.Success = true;
                res.Message = "OK";
                return res;
            }
            catch (Exception ex)
            {
                res.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return res;
            }
        }

        

        #endregion



        #region 删除

        /// <summary>
        /// 删除一个实体
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <param name="id">标识</param>
        /// <returns></returns>
        public Result DeleteOne<TEntity>(string id)
        {
            var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return DeleteOne(filter);
        }

        /// <summary>
        /// 根据条件删除实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public Result DeleteOne<TEntity>(FilterDefinition<TEntity> filter)
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var deleteRes = collection.DeleteOne(filter);
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return result;
            }
        }


        /// <summary>
        /// 异步删除一些模型
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="ids">id列表</param>
        /// <returns></returns>
        public async Task<Result> DeleteManyAsync<TEntity>(IEnumerable<string> ids) where TEntity : class, new()
        {
            //var filter = new FilterDefinitionBuilder<TEntity>().In("Id", ids);
            var result = new Result();
            foreach (var item in ids)
            {
                var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(item));
                result = await DeleteManyAsync(filter);
            }
            //var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return result;
        }

        /// <summary>
        /// 异步删除多个模型
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter">条件</param>
        /// <returns></returns>
        public async Task<Result> DeleteManyAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new()
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var deleteRes = await collection.DeleteManyAsync(filter);
                if (deleteRes.DeletedCount < 1)
                {
                    var ex = new Exception();
                    result.Message = Service.NotifyException("DeleteMany", "Some " + typeof(TEntity).Name + "s could not be deleted.", ex);
                    return result;
                }
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("DeleteMany", "Some " + typeof(TEntity).Name + "s could not be deleted.", ex);
                return result;
            }
        }



        /// <summary>
        /// 删除多个实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public Result DeleteMany<TEntity>(IEnumerable<string> ids)
        {

            var result = new Result();
            foreach (var item in ids)
            {
                var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(item));
                result = DeleteMany(filter);
            }
            //var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return result;

            // var filter = new FilterDefinitionBuilder<TEntity>().In("Id", ids);
            //return DeleteMany<TEntity>(filter);
        }

        /// <summary>
        /// 根据条件删除
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public Result DeleteMany<TEntity>(FilterDefinition<TEntity> filter)
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var deleteRes = collection.DeleteMany(filter);
                if (deleteRes.DeletedCount < 1)
                {
                    var ex = new Exception();

                    result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                    return result;
                }
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return result;
            }
        }


        /// <summary>
        /// 异步删除一个模型
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter">条件</param>
        /// <returns></returns>
        public async Task<Result> DeleteOneAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new()
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var deleteRes = await collection.DeleteOneAsync(filter);
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("DeleteOne", "Exception deleting one " + typeof(TEntity).Name, ex);
                return result;
            }
        }

        /// <summary>
        /// 异步删除一个模型
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id">标识</param>
        /// <returns></returns>
        public async Task<Result> DeleteOneAsync<TEntity>(string id) where TEntity : class, new()
        {
            var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return await DeleteOneAsync(filter);
        }


        #endregion


        #region 更新

        /// <summary>
        /// 获取和更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter"></param>
        /// <param name="update"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public TEntity GetAndUpdateOne<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update, FindOneAndUpdateOptions<TEntity, TEntity> options) where TEntity : class, new()
        {
            var result = new GetOneResult<TEntity>();
            try
            {
                var collection = GetCollection<TEntity>();
                return collection.FindOneAndUpdate(filter, update, options);
            }
            catch (Exception ex)
            {
                TEntity entity = new TEntity();
                return entity;
            }
        }



        /// <summary>
        /// 根据id更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public Result UpdateOne<TEntity>(string id, UpdateDefinition<TEntity> update)
        {
            var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return UpdateOne<TEntity>(filter, update);
        }

        /// <summary>
        /// UpdateOne with filter
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public Result UpdateOne<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update)
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var updateRes = collection.UpdateOne(filter, update);
                if (updateRes.ModifiedCount < 1)
                {
                    var ex = new Exception();

                    result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                    return result;
                }
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return result;
            }
        }

        /// <summary>
        /// 根据id列表更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public Result UpdateMany<TEntity>(IEnumerable<string> ids, UpdateDefinition<TEntity> update)
        {

            var result = new Result();
            foreach (var item in ids)
            {
                var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(item));
                result = UpdateOne(filter, update);
            }
            //var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return result;



            //var filter = new FilterDefinitionBuilder<TEntity>().In("Id", ids);
            //return UpdateOne<TEntity>(filter, update);
        }

        /// <summary>
        /// 根据条件更新
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        public Result UpdateMany<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update)
        {
            var result = new Result();
            try
            {
                var collection = GetCollection<TEntity>();
                var updateRes = collection.UpdateMany(filter, update);
                if (updateRes.ModifiedCount < 1)
                {
                    var ex = new Exception();
                    result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                    return result;
                }
                result.Success = true;
                result.Message = "OK";
                return result;
            }
            catch (Exception ex)
            {
                result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return result;
            }
        }

        #region 异步更新

        ///// <summary>
        ///// 异步更新一个模型
        ///// </summary>
        ///// <typeparam name="TEntity"></typeparam>
        ///// <param name="id">标识</param>
        ///// <param name="update">更新内容</param>
        ///// <returns></returns>
        //public async Task<Result> UpdateOneAsync<TEntity>(string id, UpdateDefinition<TEntity> update) where TEntity : class, new()
        //{
        //    var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
        //    return await UpdateOneAsync<TEntity>(filter, update);
        //}

        ///// <summary>
        ///// 异步更新一个模型
        ///// </summary>
        ///// <typeparam name="TEntity"></typeparam>
        ///// <param name="filter">更新条件</param>
        ///// <param name="update">更新内容</param>
        ///// <returns></returns>
        //public async Task<Result> UpdateOneAsync<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update) where TEntity : class, new()
        //{
        //    var result = new Result();
        //    try
        //    {
        //        var collection = GetCollection<TEntity>();
        //        var updateRes = await collection.UpdateOneAsync(filter, update);
        //        if (updateRes.ModifiedCount < 1)
        //        {
        //            var ex = new Exception();
        //            result.Message = Service.NotifyException("UpdateOne", "ERROR: updateRes.ModifiedCount < 1 for entity: " + typeof(TEntity).Name, ex);
        //            return result;
        //        }
        //        result.Success = true;
        //        result.Message = "OK";
        //        return result;
        //    }
        //    catch (Exception ex)
        //    {
        //        result.Message = Service.NotifyException("UpdateOne", "Exception updating entity: " + typeof(TEntity).Name, ex);
        //        return result;
        //    }
        //}

        ///// <summary>
        ///// 异步更新多个模型
        ///// </summary>
        ///// <typeparam name="TEntity"></typeparam>
        ///// <param name="id">更新标识列表</param>
        ///// <param name="update">更新内容</param>
        ///// <returns></returns>
        //public async Task<Result> UpdateManyAsync<TEntity>(IEnumerable<string> ids, UpdateDefinition<TEntity> update) where TEntity : class, new()
        //{
        //    var result = new Result();
        //    foreach (var item in ids)
        //    {
        //        var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(item));
        //        result = await UpdateOneAsync(filter, update);
        //    }
        //    //var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
        //    return result;



        //    // var filter = new FilterDefinitionBuilder<TEntity>().In("Id", ids);
        //    // return await UpdateOneAsync<TEntity>(filter, update);
        //}

        ///// <summary>
        ///// 异步更新多个模型
        ///// </summary>
        ///// <typeparam name="TEntity"></typeparam>
        ///// <param name="filter">更新条件</param>
        ///// <param name="update">更新内容</param>
        ///// <returns></returns>
        //public async Task<Result> UpdateManyAsync<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update) where TEntity : class, new()
        //{
        //    var result = new Result();
        //    try
        //    {
        //        var collection = GetCollection<TEntity>();
        //        var updateRes = await collection.UpdateManyAsync(filter, update);
        //        if (updateRes.ModifiedCount < 1)
        //        {
        //            var ex = new Exception();
        //            result.Message = Service.NotifyException("UpdateMany", "ERROR: updateRes.ModifiedCount < 1 for entities: " + typeof(TEntity).Name + "s", ex);
        //            return result;
        //        }
        //        result.Success = true;
        //        result.Message = "OK";
        //        return result;
        //    }
        //    catch (Exception ex)
        //    {
        //        result.Message = Service.NotifyException("UpdateMany", "Exception updating entities: " + typeof(TEntity).Name + "s", ex);
        //        return result;
        //    }
        //}

        #endregion





        #endregion


        #region 查询

        /// <summary>
        /// 根据id查询一个
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id">id</param>
        /// <returns></returns>
        public TEntity GetOne<TEntity>(string id) where TEntity : class, new()
        {
            var filter = Builders<TEntity>.Filter.Eq("_id", new ObjectId(id));
            return GetOne(filter);
        }

        /// <summary>
        /// 根据条件获取一个实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public TEntity GetOne<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new()
        {
            var res = new GetOneResult<TEntity>();
            try
            {
                var collection = GetCollection<TEntity>();
                return collection.Find(filter).SingleOrDefault();
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 根据id列表查找
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="ids"></param>
        /// <returns></returns>
        public List<TEntity> GetMany<TEntity>(IEnumerable<string> ids) where TEntity : class, new()
        {
            try
            {
                var collection = GetCollection<TEntity>();


                var list = new List<TEntity>();

                foreach (var item in ids)
                {
                    var filter = Builders<TEntity>.Filter.Eq("_id", new ObjectId(item));
                    var entity = GetOne(filter);
                    if (entity != null)
                    {
                        list.Add(entity);
                    }

                }
                return list;
            }
            catch (Exception ex)
            {
                List<TEntity> fail = null;
                //result.Message = Service.NotifyException("AddOne", "Exception adding one " + typeof(TEntity).Name, ex);
                return fail;
            }
        }

        /// <summary>
        /// 根据条件查找
        /// </summary>
        /// <typeparam name="TEntity">模型</typeparam>
        /// <param name="filter">条件</param>
        /// <param name="size">每页数量</param>
        /// <param name="index">当前页数</param>
        /// <param name="sort">升序还是降序 1 为升序排列，而-1是用于降序排列  例如（"AddDT:1"）</param>
        /// <returns></returns>
        public List<TEntity> GetMany<TEntity>(FilterDefinition<TEntity> filter, string sort = "", int? size = 0, int? index = 0) where TEntity : class, new()
        {
            try
            {
                List<TEntity> entities = new List<TEntity>();
                var collection = GetCollection<TEntity>();
                int? limit = null;
                if (size != 0 && index != 0)
                {
                    limit = size * index;
                }
                if (!string.IsNullOrEmpty(sort))
                {
                    sort = "{" + sort + "}";
                }

                if (!string.IsNullOrEmpty(sort) && limit != null)
                {
                    entities = collection.Find(filter).Limit(limit).Sort(sort).ToList();
                }
                else if (!string.IsNullOrEmpty(sort))
                {
                    entities = collection.Find(filter).Sort(sort).ToList();
                }
                else
                {
                    entities = collection.Find(filter).ToList();
                }

                if (entities != null && limit != null)
                {
                    entities = entities.Skip((Convert.ToInt32(index) - 1) * Convert.ToInt32(size)).ToList();
                }

                return entities;
            }
            catch (Exception ex)
            {
                List<TEntity> fail = null;
                return fail;
            }
        }

        /// <summary>
        /// 查找光标
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="filter"></param>
        /// <returns>A cursor for the query</returns>
        public IFindFluent<TEntity, TEntity> FindCursor<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new()
        {
            var res = new GetManyResult<TEntity>();
            var collection = GetCollection<TEntity>();
            var cursor = collection.Find(filter);
            return cursor;
        }

        /// <summary>
        /// 获取所有
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <returns></returns>
        public List<TEntity> GetAll<TEntity>() where TEntity : class, new()
        {
            var res = new GetManyResult<TEntity>();
            try
            {
                var collection = GetCollection<TEntity>();
                return collection.Find(new BsonDocument()).ToList();
            }
            catch (Exception ex)
            {
                List<TEntity> list = null;
                return list;
            }
        }


        /// <summary>
        /// 是否存在
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Exists<TEntity>(string id)
        {
            var collection = GetCollection<TEntity>();
            var query = new BsonDocument("_id", new ObjectId(id));
            var cursor = collection.Find(query);
            var count = cursor.Count();
            return (count > 0);
        }

        /// <summary>
        /// 根据id统计个数
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public long Count<TEntity>(string id)
        {
            var filter = new FilterDefinitionBuilder<TEntity>().Eq("_id", new ObjectId(id));
            return Count<TEntity>(filter);
        }

        /// <summary>
        /// 根据条件统计个数
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public long Count<TEntity>(FilterDefinition<TEntity> filter)
        {
            var collection = GetCollection<TEntity>();
            var cursor = collection.Find(filter);
            var count = cursor.Count();
            return count;
        }


        #endregion

    }

    public class Context
    {
		//39.106.186.246
		//public const string CONNECTION_STRING_NAME = "mongodb://jiangjin:jj2017@47.94.206.194:27017/bonus";
		public const string CONNECTION_STRING_NAME = "mongodb://jiangjin:jj2017@39.106.186.246:27017/bonus";
		public const string DATABASE_NAME = "bonus";

		//public const string CONNECTION_STRING_NAME = "mongodb://text:123456@203.171.237.7:27017";
		// public const string DATABASE_NAME = "JiaBang";

		private static readonly IMongoClient _client;
        private static readonly IMongoDatabase _database;

        static Context()
        {
            _client = new MongoClient(CONNECTION_STRING_NAME);
            _database = _client.GetDatabase(DATABASE_NAME);
        }

        /// <summary>
        /// The private GetCollection method
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <returns></returns>
        public IMongoCollection<TEntity> GetCollection<TEntity>()
        {
            return _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLower() + "s");
        }

    }
    public static class Service
    {

        public static string NotifyException(string FunctionName, string Context, Exception ex)
        {
            string source = FunctionName + ": " + Context;
            source = GetAllInformation(ex, source);
            Debug.WriteLine(source);
            return source;
        }

        /// <summary>
        /// Get all exception information
        /// </summary>
        /// <param name="exception"></param>
        /// <param name="information"></param>
        /// <returns></returns>
        public static string GetAllInformation(Exception exception, string source)
        {

            var sb = new StringBuilder();
            sb.AppendLine("********** " + DateTime.Now.ToLongDateString() + "**********");

            while (exception != null)
            {
                sb.AppendLine("Inner Exception Type: ");
                sb.AppendLine(exception.InnerException.GetType().ToString());
                sb.AppendLine("Inner Exception: ");
                sb.AppendLine(exception.InnerException.Message);
                sb.AppendLine("Inner Source: ");
                sb.AppendLine(exception.InnerException.Source);
                if (exception.InnerException.StackTrace != null)
                {
                    sb.AppendLine("Inner Stack Trace: ");
                    sb.AppendLine(exception.InnerException.StackTrace);
                }
                sb.AppendLine("Exception Type: ");
                sb.AppendLine(sb.GetType().ToString());
                sb.AppendLine("Exception: " + exception.Message);
                sb.AppendLine("Source: " + source);
                sb.AppendLine("Stack Trace: ");
                if (exception.StackTrace != null)
                {
                    sb.AppendLine(exception.StackTrace);
                    sb.AppendLine();
                }
                exception = exception.InnerException;
            }

            return sb.ToString();
        }



    }
}